<template>
  <div class="preview-print-spread-sheet" @drop.prevent.stop>
    <el-header class="step-header"
      style="overflow: hidden; background: white; height: 72px; border-bottom: 1px solid #ebeef5">
      <el-row type="flex" justify="space-between" align="middle" style="height: 100%">
        <div class="title" style="width: 200px; height: 40px; line-height: 40px; display: flex">
          <i class="header-logo logo online-icon icon-orange-icon" style="font-size: 40px" />
          <span style="font-size: 22px; color: #333333; font-weight: bold">兆维科技打印预览</span>
        </div>
        <el-row class="operation" type="flex" justify="end">
          <el-button type="primary" :icon="Printer" @click="doPrint" :loading="waitShowPrinter"
            style="width: 85px">打印</el-button>
          <el-button :icon="Download" @click="downloadFile" style="width: 85px">PDF</el-button>
          <el-button @click="onCancel" style="width: 85px">退出</el-button>
        </el-row>
      </el-row>
    </el-header>
    <el-main style="
        background: #f6f6f6;
        padding: 16px;
        height: calc(100vh - 72px);
        background: white;
        display: flex;
        justify-content: center;
        position: relative;
      ">
      <div v-html="previewHtml" v-loading="spinning" ref="previewContainer"></div>
      <!-- Draggable Signature/Stamp Layer -->
      <div v-if="isDraggingEnabled" ref="dragLayer" class="drag-layer" @mousedown="startDragging"
        :style="{ left: layerPosition.left + 'px', top: layerPosition.top + 'px' }">
        <img ref="imgRef" :src="imageSrc" alt="Signature/Stamp" class="stamp-image" @dragstart.prevent />
        <div class="layer-buttons">
          <el-button size="small" type="primary" @click.stop="confirmAction">确定</el-button>
          <el-button size="small" @click.stop="deleteAction">取消</el-button>
        </div>
      </div>
      <div style="
          position: fixed;
          left: 16px;
          top: 88px;
          display: flex;
          flex-direction: column;
          align-items: end;
          row-gap: 10px;
        ">
        <el-button :icon="EditPen" @click="addSignature"> 签名 </el-button>
        <el-button :icon="Stamp" @click="addStamp"> 盖章 </el-button>
      </div>
    </el-main>
  </div>
</template>

<script lang="ts" setup>
import { Printer, Download, Stamp, EditPen } from '@element-plus/icons-vue';
import { hiprint } from '../index.js';
import { ReportPrintController } from '@/api/report';
import { ANY_OBJECT } from '@/types/generic';
import { Dialog } from '@/components/Dialog';
import { DialogProp } from '@/components/Dialog/types';
import ImgStamp from '@/assets/img/stamp.png';
import SignaturePad from '@/components/SignaturePad/signatureDlg.vue';
import { SignatureInfo } from '@/components/SignaturePad/signature.js';

const props = withDefaults(
  defineProps<{
    printId: string;
    printParam: Array<ANY_OBJECT>;
    printName?: string;
    // 当使用Dialog.show弹出组件时，须定义该prop属性，以便对dialog进行回调
    dialog?: DialogProp<boolean>;
  }>(),
  {
    printName: '兆维科技打印预览',
  },
);

const spinning = ref(false);
const waitShowPrinter = ref(false);
let hiprintTemplate: ANY_OBJECT = {};
let printData = {};
const previewContainer = ref<HTMLElement>();
const previewHtml = ref('');

const onCancel = () => {
  props.dialog?.cancel();
};

const getHiprintInfo = async (
  printId: string,
  printParam: Array<ANY_OBJECT>,
): Promise<ANY_OBJECT> => {
  let params = {
    printId: printId,
    printParam: printParam,
    renderType: 5,
  };

  let res: ANY_OBJECT = await ReportPrintController.printPreview(params);
  console.log('printPreview =>', res);
  return res.data;
};

const drawPage = (printData: ANY_OBJECT) => {
  const htmlResult = hiprintTemplate.getHtml(printData);
  previewHtml.value = htmlResult.prop('outerHTML');
};

const show = (printId: string, printParam: Array<ANY_OBJECT>, width = 210) => {
  getHiprintInfo(printId, printParam).then(res => {
    let hiprintDataJson = res.hiprintDataJson ? JSON.parse(res.hiprintDataJson) : {};

    hiprintTemplate.update(hiprintDataJson);
    let showWidth = width;
    if (hiprintTemplate.editingPanel && hiprintTemplate.editingPanel.width) {
      showWidth = hiprintTemplate.editingPanel.width;
    } else if (
      hiprintTemplate.printPanels &&
      hiprintTemplate.printPanels[0] &&
      hiprintTemplate.printPanels[0].width
    ) {
      showWidth = hiprintTemplate.printPanels[0].width;
    }
    spinning.value = true;

    printData = res.hiprintData;
    setTimeout(() => {
      drawPage(printData);
      spinning.value = false;
    }, 500);
  });
};

const doPrint = () => {
  waitShowPrinter.value = true;
  hiprintTemplate.print(
    printData,
    {
      /*
      styleHandler: () => {
        // 这里拼接成放html->head标签内的css/style
        // 1.例如：使用hiprin官网的样式
        let css =
          '<link href="http://hiprint.io/Content/hiprint/css/print-lock.css" media="print" rel="stylesheet">';
        return css;
      }
      */
    },
    {
      callback: () => {
        waitShowPrinter.value = false;
        console.log('浏览器打印窗口已打开');
      },
    },
  );
};

const downloadFile = () => {
  console.log('下载文件', props.printName);
  try {
    hiprintTemplate.toPdf(printData, props.printName);
  } catch (e) {
    console.log('下载文件异常', e);
  }
};

onMounted(() => {
  console.log('printPreview mounted');
  hiprintTemplate = new hiprint.PrintTemplate();
  show(props.printId, props.printParam);
});

// 以下为签名/盖章功能
const dragLayer = ref<HTMLElement>();
const imgRef = ref<HTMLImageElement>();
const isDraggingEnabled = ref(false); // Show/hide layer
const imageSrc = ref('');
const layerPosition = reactive({ left: 0, top: 0 });

const unitConverter = {
  dpi: 96,
  pxToMm(px: number): number {
    return (px * 25.4) / unitConverter.dpi;
  },
  mmToPt(mm: number): number {
    return (mm * 72) / 25.4;
  },
  pxToPt(px: number): number {
    return unitConverter.mmToPt(unitConverter.pxToMm(px));
  },
};

const pxToPt = (px: number): number => {
  // 1px = 72/96 inch
  return (px * 72) / 96;
};

// 获取元素相对父容器的坐标
const getContainerRelativePosition = (el: HTMLElement) => {
  const container = el.parentElement; // 父容器是 el-main
  if (!container) return { x: 0, y: 0 };

  // const containerRect = container.getBoundingClientRect();
  // const elRect = el.getBoundingClientRect();

  // return {
  //   x: elRect.left - containerRect.left,
  //   y: elRect.top - containerRect.top
  // };
  // 获取容器滚动偏移
  const scrollLeft = container.scrollLeft;
  const scrollTop = container.scrollTop;

  // 计算元素相对容器位置（包含滚动）
  return {
    x: el.offsetLeft - scrollLeft, // 使用 offsetLeft 而非 getBoundingClientRect
    y: el.offsetTop - scrollTop,
  };
};

// Bounding area (e.g., relative to previewContainer)
let dragBoundaries = {
  minX: 0,
  minY: 0,
  maxX: 200,
  maxY: 500,
};

let isDragging = false;
let offsetX = 0;
let offsetY = 0;

const startDragging = (e: MouseEvent) => {
  if (!dragLayer.value) return;

  isDragging = true;

  // 使用 dragLayer.getBoundingClientRect() 来获取真正渲染的位置
  const rect = dragLayer.value.getBoundingClientRect();

  // 正确计算点击位置相对于 dragLayer 左上角的偏移
  offsetX = e.clientX - rect.left;
  offsetY = e.clientY - rect.top;

  // console.log('开始拖动', layerPosition.left, layerPosition.top);
  // console.log('开始拖动', rect.left, rect.top,e.clientX, e.clientY,  offsetX, offsetY)

  document.addEventListener('mousemove', onDragging);
  document.addEventListener('mouseup', stopDragging);
};

const onDragging = (e: MouseEvent) => {
  if (!isDragging) return;

  // 获取父容器位置
  const container = previewContainer.value?.parentElement;
  if (!container) return;

  // 获取容器滚动偏移
  const scrollLeft = container.scrollLeft;
  const scrollTop = container.scrollTop;

  const { left: containerLeft, top: containerTop } = container.getBoundingClientRect();

  // 计算鼠标位置时包含滚动偏移
  const newX = e.clientX - offsetX - containerLeft + scrollLeft;
  const newY = e.clientY - offsetY - containerTop + scrollTop;

  // 应用边界限制
  layerPosition.left = Math.max(dragBoundaries.minX, Math.min(newX, dragBoundaries.maxX));
  layerPosition.top = Math.max(dragBoundaries.minY, Math.min(newY, dragBoundaries.maxY));
};

const stopDragging = () => {
  isDragging = false;
  document.removeEventListener('mousemove', onDragging);
  document.removeEventListener('mouseup', stopDragging);
};

const addImageToPanel = (
  imageUrl: string,
  width: number,
  height: number,
  top: number,
  left: number,
  zIndex = 9,
) => {
  var panel = hiprintTemplate.getPanel(0); // 添加面板

  width = unitConverter.pxToPt(width);
  height = unitConverter.pxToPt(height);
  top = unitConverter.pxToPt(top);
  left = unitConverter.pxToPt(left);

  // 添加图片
  panel.addPrintImage({
    options: {
      width,
      height,
      top,
      left,
      src: imageUrl,
      zIndex,
    },
  });

  drawPage(printData);
};

const confirmAction = () => {
  isDraggingEnabled.value = false;

  const previewEl = previewContainer.value;
  const img = imgRef.value;
  if (!previewEl || !img) return;

  const imgRect = img.getBoundingClientRect();
  const printTemplateRect = previewEl
    .querySelector('.hiprint-printTemplate')!
    .getBoundingClientRect();

  // 所有位置都相对于 .hiprint-printTemplate 左上角计算
  const leftPx = imgRect.left - printTemplateRect.left;
  const topPx = imgRect.top - printTemplateRect.top;

  addImageToPanel(imageSrc.value, imgRect.width, imgRect.height, topPx, leftPx);
};

const deleteAction = () => {
  console.log('取消签章/签名');
  isDraggingEnabled.value = false;
};

const loadImageAsync = (imgElement: HTMLImageElement): Promise<void> => {
  console.log('图片是否加载完成', imgElement.complete);
  if (imgElement.complete && imgElement.naturalWidth > 0) {
    return Promise.resolve();
  }

  return new Promise((resolve, reject) => {
    imgElement.onload = () => {
      imgElement.onload = null;
      resolve();
    };
    imgElement.onerror = () => {
      imgElement.onload = null;
      reject(new Error('Image load failed'));
    };
  });
};

const addStampOrSignature = async (imgUrl: string | undefined, scale = 1) => {
  if (!imgUrl) return;
  const el = previewContainer.value;
  if (!el) return;
  const elMain = previewContainer.value?.parentElement;
  if (!elMain) return;

  // 获取容器相对父级（el-main）的位置
  const { x: containerX, y: containerY } = getContainerRelativePosition(el);

  const scrollLeft = elMain.scrollLeft;
  const scrollTop = elMain.scrollTop;

  console.log('scrollTop', scrollTop);
  console.log('containerX', containerX);
  console.log('containerY', containerY);

  // 设置初始位置为容器左上角（带5px偏移）
  layerPosition.left = scrollLeft + 5;
  layerPosition.top = scrollTop + 15 + 5; // 加上15px的偏移，因为预览容器有 margin-top: 15px

  // 获取容器实际内容尺寸
  const contentWidth = el.scrollWidth;
  const contentHeight = el.scrollHeight;

  // 设置边界范围（基于父容器坐标系）
  dragBoundaries = {
    minX: containerX,
    minY: containerY + scrollTop + 15, // 补偿 margin-top
    maxX: containerX + scrollLeft + contentWidth,
    maxY: containerY + scrollTop + contentHeight,
  };

  // 启用层并加载图片
  isDraggingEnabled.value = true;
  imageSrc.value = imgUrl;

  // 修正边界（考虑拖拽层自身尺寸）
  await nextTick();

  const dragEl = dragLayer.value;
  const img = imgRef.value;
  if (!dragEl || !img) return;

  try {
    await loadImageAsync(img);
    let { width, height } = img.getBoundingClientRect();
    //console.log('图片尺寸', width, height)

    width *= scale;
    height *= scale;

    img.style.width = width + 'px';

    dragBoundaries.maxX -= width;
    dragBoundaries.maxY -= height;

    // 确保不会越界
    layerPosition.left = Math.max(
      dragBoundaries.minX,
      Math.min(layerPosition.left, dragBoundaries.maxX),
    );
    layerPosition.top = Math.max(
      dragBoundaries.minY,
      Math.min(layerPosition.top, dragBoundaries.maxY),
    );
  } catch (e) {
    console.error('图片加载失败', e);
    isDraggingEnabled.value = false;
  }
};

const addSignature = () => {
  Dialog.show<SignatureInfo>(
    '手写签名',
    SignaturePad,
    {
      area: ['400px'],
    },
    {
      width: '100%',
      height: '150px',
      autoTrim: true,
    },
  ).then(res => {
    //console.log(res)
    // 手写板进行了缩放，图片实际大小会改变，这里按照手写板的缩放比例进行缩放,所见即所得
    const ratio = Math.max(window.devicePixelRatio || 1, 1);
    addStampOrSignature(res.data, 1 / ratio);
  });
};

const addStamp = () => {
  addStampOrSignature(ImgStamp);
};
</script>

<style lang="scss" scoped>
.preview-print-spread-sheet {
  position: fixed;
  top: 0px;
  left: 0px;
  width: 100vw;
  height: 100vh;
  z-index: 100;
  background: #f9f9f9;
}

.drag-layer {
  position: absolute;
  z-index: 9999;
  //padding: 8px;
  padding: 0;
  background: rgba(255, 255, 255, 0.3);
  //border: 1px dashed #409EFF;
  //border-radius: 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  cursor: move;
}

.stamp-image {
  //max-width: 100px;
  //max-height: 100px;
  user-drag: none;
  -webkit-user-drag: none;
  pointer-events: none;
}

.layer-buttons {
  margin-top: 6px;
  display: flex;
  gap: 8px;
}
</style>
